/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hudomju.swipe.widget;

import com.hudomju.swipe.adapter.BaseAdapter;
import com.hudomju.swipe.adapter.SwipeDirection;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;

import ohos.app.Context;

import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

/**
 * Item布局
 */
public class ItemLayout extends DirectionalLayout implements Component.TouchEventListener,
        Component.BindStateChangedListener {
    private double mViewWidth = 1; // 1而不是0以防止被零除
    private boolean mFadeOut = true; // 淡出
    private SwipeDirection mDirection = SwipeDirection.DIRECTION_NEUTRAL;
    private boolean mFar = false;
    private double mDownX;
    private double mDownY;
    private boolean isSlide = false;
    private int touchSlop;
    private float mFarSwipeFraction = 0.1f;
    private BaseAdapter.Callbacks callBacks;
    private int mPosition;

    /**
     * ItemLayout构造方法
     *
     * @param context 上下文
     */
    public ItemLayout(Context context) {
        super(context);
        init();
    }

    /**
     * ItemLayout构造方法
     *
     * @param context 上下文
     * @param attrSet 属性
     */
    public ItemLayout(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init();
    }

    /**
     * ItemLayout构造方法
     *
     * @param context 上下文
     * @param attrSet 属性
     * @param styleName 样式名称
     */
    public ItemLayout(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
    }

    public void init() {
        touchSlop = 8;
        isSlide = false;
        setTouchEventListener(this);
        setBindStateChangedListener(this);
    }

    public boolean ifSlideLeft(Component component, TouchEvent ev) {
        switch (ev.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                MmiPoint point = ev.getPointerPosition(ev.getIndex());
                mDownX = point.getX();
                mDownY = point.getY();
                break;
            case TouchEvent.POINT_MOVE:
                MmiPoint point1 = ev.getPointerPosition(ev.getIndex());
                double deltaX = point1.getX() - mDownX;
                double deltaY = point1.getY() - mDownY;
                if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > touchSlop) {
                    isSlide = true;
                } else {
                    isSlide = false;
                }
        }
        return isSlide;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if(ifSlideLeft(component, touchEvent)) {
            if (mViewWidth < 2) {
                mViewWidth = component.getWidth();
            }
            MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex());
            double eventY = point.getY();
            double eventX = point.getX();
            if (eventX < 0) {
                eventX = 0;
            } else if (eventX > mViewWidth) {
                eventX = mViewWidth;
            } else {
                eventX = point.getX();
            }
            switch (touchEvent.getAction()) {
                case TouchEvent.PRIMARY_POINT_DOWN: {
                    mDownY = eventY;
                    mDownX = eventX;
                    return true;
                }

                case TouchEvent.CANCEL:
                case TouchEvent.PRIMARY_POINT_UP: {
                    if (this.callBacks != null) {
                        this.callBacks.onSwipe(mPosition, mDirection);
                    }
                    if (this.callBacks != null) {
                        this.callBacks.shouldDismiss(mPosition, mDirection);
                    }
                    mDirection = SwipeDirection.DIRECTION_NEUTRAL;
                    component.setTranslationX(0);
                    component.setAlpha(1);
                    component.invalidate();
                    break;
                }

                case TouchEvent.POINT_MOVE: {
                    if (mDownY - eventY > 10 || mDownY - eventY < -10) {
                        break;
                    }
                    onMove(component, touchEvent, eventX, eventY);
                }
            }
        }
        return true;
    }

    private boolean onMove(Component component, TouchEvent touchEvent, double eventX, double eventY){
        double deltaX = eventX - mDownX;
        if (mDirection.isLeft() && deltaX > 0 || mDirection.isRight() && deltaX < 0) {
            mFar = false;
        }
        if (!mFar && Math.abs(deltaX) > mViewWidth * mFarSwipeFraction) {
            mFar = true;
        }
        if (!mFar) {
            mDirection = (deltaX > 0 ? SwipeDirection.DIRECTION_NORMAL_RIGHT : SwipeDirection.DIRECTION_NORMAL_LEFT);
        } else {
            mDirection = (deltaX > 0 ? SwipeDirection.DIRECTION_FAR_RIGHT : SwipeDirection.DIRECTION_FAR_LEFT);
        }
        if (this.callBacks != null) {
            if (this.callBacks.hasActions(mPosition, mDirection)) {
                if (mDownX < (mViewWidth * mFarSwipeFraction)) {
                    component.setTranslationX((float) eventX);
                } else {
                    component.setTranslationX((float)(eventX - mViewWidth));
                }
                // 设置透明度
                if (mFadeOut) {
                    component.setAlpha(Math.max(0, (float) Math.min(1, 1 - 2 * Math.abs(deltaX) / mViewWidth)));
                }
                component.setTranslationY(0);
                component.invalidate();
            }
        }
        return true;
    }

    /**
     * 设置回调
     *
     * @param callBack 回调
     */
    public void setCallBack(BaseAdapter.Callbacks callBack) {
        this.callBacks = callBack;
    }

    /**
     * 设置当前位置
     *
     * @param position 位置
     */
    public void setPosition(int position) {
        this.mPosition = position;
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        AnimatorValue value = new AnimatorValue();
        value.setCurveType(Animator.CurveType.LINEAR);
        value.setDuration(1000);
        value.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float val) {
            }
        });
        value.start();
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
    }
}
